#include "redimension.h"
#include "GraphicsArea/drawingarea.h"
#include <QtGui>
#include<iostream>
#include <math.h>


using namespace std;

Redimension::Redimension (DrawingArea*  drawing, QWidget *parent)
{

    this->drawing  = drawing ;
    ui_redimen = new Ui_redimen::Dialog();
    QDialog* dialogRedim;
    dialogRedim = new QDialog(parent);
    ui_redimen->setupUi(dialogRedim, drawing->getWidth(), drawing->getHeight());
    dialogRedim->show();
    ui_redimen->newWidth->setMaximum(100000);
    ui_redimen->newHeight->setMaximum(100000);
    ui_redimen->newWidth->setValue(drawing->getWidth());
    ui_redimen->newHeight->setValue(drawing->getHeight());
    QObject::connect(ui_redimen->Reset,SIGNAL(released()), this , SLOT(resetValue()));
    QObject::connect(ui_redimen->Apply,SIGNAL(released()), this , SLOT(redimensionImage()));



}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Réinisialiser la Taille de l'image
void Redimension::resetValue()
{
    ui_redimen->newWidth->setValue(drawing->getWidth());
    ui_redimen->newHeight->setValue(drawing->getHeight());

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   Redimensionner l'image

void Redimension::redimensionMoyennageLayer(Layer* layer, int newWidth, int newHeight)
{
    QImage* newImage = new QImage(newWidth, newHeight, layer->getImage()->format());


    double oldPointX,oldPointY;
    double xDiminution, yDiminution;
    double distanceX, distanceY;


    if(((double) layer->getWidth()) < ((double) newWidth)){
        // we are in a case of augmentation of the width original
        xDiminution  = ((double) layer->getWidth()) / ((double) newWidth - 1);
    }else{
        // we are in a case of diminution or the height
        xDiminution  = ((double) layer->getWidth()) / ((double) newWidth);
    }
    if(((double) layer->getHeight()) / ((double) newHeight)){
        yDiminution = ((double) layer->getHeight()) / ((double) newHeight - 1);
    }else{
        yDiminution = ((double) layer->getHeight()) / ((double) newHeight);
    }

    for(int y = 0;y < newHeight; y++)
    {
        for(int x = 0;x < newWidth; x++)
        {
            oldPointX = x * xDiminution;
            oldPointY = y * yDiminution;


            QRgb rgbPointTopLeft = layer->getImage()->pixel(oldPointX, oldPointY);

            QRgb rgbPointTopRight = layer->getImage()->pixel(oldPointX + 1, oldPointY);

            QRgb rgbPointBottomLeft = layer->getImage()->pixel(oldPointX, oldPointY + 1);

            QRgb rgbPointBottomRight = layer->getImage()->pixel(oldPointX + 1, oldPointY + 1);


            distanceX = oldPointX - ((int)oldPointX);
            distanceY = oldPointY - ((int)oldPointY);

            int red = (qRed(rgbPointTopLeft) * (1.0 - distanceX) + qRed(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qRed(rgbPointBottomLeft) * (1.0 - distanceX) + qRed(rgbPointBottomRight) * (distanceX)) * distanceY;
            int green = (qGreen(rgbPointTopLeft) * (1.0 - distanceX) + qGreen(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qGreen(rgbPointBottomLeft) * (1.0 - distanceX) + qGreen(rgbPointBottomRight) * (distanceX)) * distanceY;
            int blue = (qBlue(rgbPointTopLeft) * (1.0 - distanceX) + qBlue(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qBlue(rgbPointBottomLeft) * (1.0 - distanceX) + qBlue(rgbPointBottomRight) * (distanceX)) * distanceY;
            int alpha = (qAlpha(rgbPointTopLeft) * (1.0 - distanceX) + qAlpha(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qAlpha(rgbPointBottomLeft) * (1.0 - distanceX) + qAlpha(rgbPointBottomRight) * (distanceX)) * distanceY;



            newImage->setPixel(x, y, qRgba(red, green, blue, alpha));
        }
    }

    layer->setImage(newImage);

 }

 void Redimension::redimensionBilinearLayer(Layer* layer, int newWidth, int newHeight)
{
    // redimensionnemnent bilinear


    QImage* newImage = new QImage(newWidth, newHeight, layer->getImage()->format());


    double oldPointX,oldPointY;
    double xAugmentation, yAugmentation;
    double distanceX, distanceY;



    xAugmentation  = ((double) layer->getWidth()) / ((double) newWidth);

    yAugmentation = ((double) layer->getHeight()) / ((double) newHeight);

    for(int y = 0;y < newHeight; y++)
    {
        for(int x = 0;x < newWidth; x++)
        {
            oldPointX = x * xAugmentation;
            oldPointY = y * yAugmentation;


            QRgb rgbPointTopLeft = layer->getImage()->pixel(oldPointX, oldPointY);

            QRgb rgbPointTopRight = layer->getImage()->pixel(min((int) oldPointX + 1, layer->getWidth() - 1), oldPointY);

            QRgb rgbPointBottomLeft = layer->getImage()->pixel(oldPointX, min((int) oldPointY + 1, layer->getHeight() - 1));

            QRgb rgbPointBottomRight = layer->getImage()->pixel(min((int) oldPointX + 1, layer->getWidth() - 1), min((int) oldPointY + 1, layer->getHeight() - 1));


            distanceX = oldPointX - ((int)oldPointX);
            distanceY = oldPointY - ((int)oldPointY);

            int red = (qRed(rgbPointTopLeft) * (1.0 - distanceX) + qRed(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qRed(rgbPointBottomLeft) * (1.0 - distanceX) + qRed(rgbPointBottomRight) * (distanceX)) * distanceY;
            int green = (qGreen(rgbPointTopLeft) * (1.0 - distanceX) + qGreen(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qGreen(rgbPointBottomLeft) * (1.0 - distanceX) + qGreen(rgbPointBottomRight) * (distanceX)) * distanceY;
            int blue = (qBlue(rgbPointTopLeft) * (1.0 - distanceX) + qBlue(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qBlue(rgbPointBottomLeft) * (1.0 - distanceX) + qBlue(rgbPointBottomRight) * (distanceX)) * distanceY;
            int alpha = (qAlpha(rgbPointTopLeft) * (1.0 - distanceX) + qAlpha(rgbPointTopRight) * (distanceX)) * (1.0 - distanceY)
            + (qAlpha(rgbPointBottomLeft) * (1.0 - distanceX) + qAlpha(rgbPointBottomRight) * (distanceX)) * distanceY;



            newImage->setPixel(x, y, qRgba(red, green, blue, alpha));
        }
    }

    layer->setImage(newImage);

}

void Redimension::redimensionImage()
{
    if(ui_redimen->TypeResizeCombo->currentText() == "Seam Carving"){
        cout << "Seam Carving" << endl;
        width = ui_redimen->newWidth->value();
        height = ui_redimen->newHeight->value();

        double scaleX = ((double) width) / ((double) drawing->getWidth());
        double scaleY = ((double) height) / ((double) drawing->getHeight());
        // redimensioonner tt les claques
        list<Layer*> listLayers =  drawing->getLayers();
        for (int i= 0  ; i < drawing->getLayersCount(); i++  )
        {
            Layer* layer = listLayers.back();
            //redimensionBilinearLayer(layer, layer->getWidth() * scaleX, layer->getHeight() * scaleY);
            smartResize(layer, layer->getWidth() * ((double) scaleX), layer->getHeight() * ((double) scaleY));
            //layer->setSizeBoundingRect(width, height);
            //layer->setPos(layer->x() * scaleX, layer->y() * scaleY);
            listLayers.pop_back();
        }

        //drawing->resize(width, height);

    }else{
        cout << "bilineaire" << endl;
        width = ui_redimen->newWidth->value();
        height = ui_redimen->newHeight->value();

        double scaleX = ((double) width) / ((double) drawing->getWidth());
        double scaleY = ((double) height) / ((double) drawing->getHeight());
        // redimensioonner tt les claques
        list<Layer*> listLayers =  drawing->getLayers();
        for (int i= 0  ; i < drawing->getLayersCount(); i++  )
        {
            Layer* layer = listLayers.back();
            redimensionBilinearLayer(layer, layer->getWidth() * scaleX, layer->getHeight() * scaleY);

            layer->setSizeBoundingRect(width, height);
            layer->setPos(layer->x() * scaleX, layer->y() * scaleY);
            listLayers.pop_back();
        }

        drawing->resize(width, height);
    }

}
void Redimension::smartResize(Layer* layer, int newWidth, int newHeight){

    seamCarving = new SeamCarvingResize(drawing, layer, newWidth, newHeight);
    seamCarving->start();
    //QObject::connect(seamCarving, SIGNAL(finished()), this, SLOT(askResizeDrawing()));
}

void Redimension::askResizeDrawing(){
    drawing->resize(width, height);

}
